package com.wlcb.jpower.chat.service.customer.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wlcb.jpower.chat.dbs.dao.file.ChatFileDao;
import com.wlcb.jpower.chat.entity.customer.TblCustomerMsg;
import com.wlcb.jpower.chat.entity.file.TbChatFile;
import com.wlcb.jpower.chat.service.customer.ChatService;
import com.wlcb.jpower.chat.service.customer.CustomerMsgService;
import com.wlcb.jpower.chat.service.customer.CustomerSettingService;
import com.wlcb.jpower.constant.ChatConfigConstant;
import com.wlcb.jpower.constant.ChatConstant;
import com.wlcb.jpower.constant.DBConstant;
import com.wlcb.jpower.im.cache.ImChatRecordCache;
import com.wlcb.jpower.im.cache.SessionCache;
import com.wlcb.jpower.im.model.DataPacket;
import com.wlcb.jpower.module.base.exception.BusinessException;
import com.wlcb.jpower.module.base.vo.ResponseData;
import com.wlcb.jpower.module.common.utils.*;
import com.wlcb.jpower.properties.JpowerChatProperties;
import com.wlcb.jpower.utils.RedisHelpUtils;
import com.wlcb.jpower.utils.WxMpInstance;
import com.wlcb.jpower.wx.mp.wxuser.UserInfoResponse;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;
import me.chanjar.weixin.mp.builder.kefu.WxMsgMenuBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@Slf4j
@Service("chatServiceImpl")
public class ChatServiceImpl implements ChatService {

    @Autowired
    private CustomerMsgService customerMsgService;
    @Autowired
    private CustomerSettingService settingService;
    @Autowired
    private ChatFileDao chatFileDao;
    @Autowired
    private JpowerChatProperties properties;

    /**
     * 获取待接入列表
     *
     * @return
     */
    @Override
    public List<DataPacket.Wait> getWaitUsers() {
        List<TblCustomerMsg> list = customerMsgService.list(new QueryWrapper<TblCustomerMsg>().lambda()
                .eq(TblCustomerMsg::getIsDeleted, 0)
                .eq(TblCustomerMsg::getStatus, DBConstant.CustomerMsgEnum.WAIT_ACCESS.getType()));
        List<DataPacket.Wait> waits = new ArrayList<>();
        for (TblCustomerMsg msg : list) {
            List<DataPacket> records = ImChatRecordCache.getInstance(msg.getOpenid(), msg.getId()).getRecords();
            DataPacket.Wait wait = new DataPacket.Wait();
            wait.setOpenid(msg.getOpenid());
            wait.setAppId(msg.getAppid());
            wait.setContent(JSON.toJSONString(records));
            wait.setDialogId(msg.getId());
            wait.setSpecial(msg.getIsSpecial() != 0);
            waits.add(wait);
        }
        return waits;
    }


    @Override
    public ResponseData connectUser(String cid, String uid, String appId) {
        RedisHelpUtils.RedisLock redisLock = RedisHelpUtils.getRedisLock();
        //避免多客服接入同一人
        boolean tryLock = redisLock.tryLock(uid);
        if (tryLock) {
            try {

                if (!SessionCache.isSession(cid)) {
                    return ReturnJsonUtil.fail("当前会话未找到");
                }
                ImChatRecordCache imChatRecordCache = ImChatRecordCache.getInstance(uid);
                if (Fc.isNull(imChatRecordCache)) {
                    return ReturnJsonUtil.fail("该用户会话未找到");
                }
                TblCustomerMsg customerMsg = customerMsgService.getById(imChatRecordCache.getDialogId());
                if (Fc.isNotBlank(customerMsg.getCurrentCid())) {
                    if (cid.equals(customerMsg.getCurrentCid())) {
                        return ReturnJsonUtil.fail("您已经接入该用户");
                    }
                    return ReturnJsonUtil.fail("该用户已经被" + customerMsg.getCurrentCid() + "接入");
                }

                long count = customerMsgService.findByCid(cid);
                if (count >= 100) {
                    return ReturnJsonUtil.fail("接入数量已经达到<" + count + ">人");
                }
                TblCustomerMsg msg = new TblCustomerMsg();
                msg.setFirstCid(cid);
                msg.setCurrentCid(cid);
                msg.setStatus(DBConstant.CustomerMsgEnum.ACCESSED.getType());
                msg.setId(customerMsg.getId());
                if (!customerMsgService.modifyById(msg)) {
                    return ReturnJsonUtil.fail("更新会话失败");
                } else {
                    imChatRecordCache.setCid(cid);
                }

                WxMpUser wxMpUser = WxMpInstance.getWxMp().switchoverTo(appId).getUserService().userInfo(uid);
                UserInfoResponse user = BeanUtil.copyProperties(wxMpUser, UserInfoResponse.class);
                UserInfoResponse userInfoResponse = toUserInfoResponse(wxMpUser, user, customerMsg);
                userInfoResponse.setIsSpecial(customerMsg.getIsSpecial() != 0);
                DataPacket userInfo = DataPacket.system(customerMsg.getId(),
                        uid, appId, userInfoResponse.toString(), ChatConstant.ChatActionEnum.USERINFO.type);
                SessionCache.write(cid, userInfo);

                String reply = settingService.findCidIsAutoReply(cid);
                if (Fc.isNotBlank(reply)) {
                    WxMpInstance.getWxMp().switchoverTo(appId).getKefuService().sendKefuMessage(WxMpKefuMessage.TEXT().toUser(uid).content(reply).build());
                }
                //推送待接入列表
                DataPacket wait = DataPacket.wait(getWaitUsers(), ChatConfigConstant.UserType.CUSTOMER);
                SessionCache.writeAll(wait);

                //推送所有聊天记录
                List<DataPacket> records = imChatRecordCache.getRecords();
                for (DataPacket packet : records) {
                    SessionCache.write(cid, packet);
                }
                //推送系统消息
                DataPacket system = DataPacket.system(customerMsg.getId(), uid, appId, "系统消息：坐席<" + cid + ">接入此新用户", ChatConstant.ChatActionEnum.CUSTOMER_USER_MESSAGE.type);
                SessionCache.write(cid, system);
                imChatRecordCache.setRecords(system);
                return ReturnJsonUtil.ok("接入成功");
            } catch (Exception e) {
                e.printStackTrace();
                return ReturnJsonUtil.fail("接入失败", e.getMessage());
            } finally {
                redisLock.runlock(uid);
            }
        }
        return ReturnJsonUtil.fail("正在被他人接入中");
    }

    @Override
    public ResponseData transferUser(String cid, String tcid, String uid, String appId) {
        try {
            if (!settingService.findCidAllowTransfer(tcid)) {
                return ReturnJsonUtil.fail("转接失败：对方开启了转接限制功能");
            }
            if (cid.equals(tcid)) {
                return ReturnJsonUtil.fail("不可转接给自己");
            }
            if (!SessionCache.isSession(tcid)) {
                return ReturnJsonUtil.fail("目标客服不在线无法转接");
            }
            if (!SessionCache.isSession(cid)) {
                return ReturnJsonUtil.fail("您已离线，请刷新页面重新连接！");
            }
            ImChatRecordCache recordCache = ImChatRecordCache.getInstance(uid);
            if (Fc.isNull(recordCache)) {
                return ReturnJsonUtil.fail("用户会话不存在");
            }
            long count = customerMsgService.findByCid(tcid);
            if (count >= 100) {
                return ReturnJsonUtil.fail("该客服<" + tcid + ">接入数量已经达到<" + count + ">人");
            }
            TblCustomerMsg customerMsg = customerMsgService.getById(recordCache.getDialogId());

            DataPacket system = DataPacket.system(recordCache.getDialogId(), uid,
                    appId, "系统消息：坐席 <" + cid + ">,给坐席<" + tcid + ">转接了一个用户！", ChatConstant.ChatActionEnum.CUSTOMER_USER_MESSAGE.type);

            SessionCache.write(tcid, system);

            TblCustomerMsg msg = new TblCustomerMsg();
            msg.setCurrentCid(tcid);
            msg.setId(recordCache.getDialogId());
            if (!customerMsgService.modifyById(msg)) {
                return ReturnJsonUtil.fail("修改会话信息失败");
            } else {
                recordCache.setCid(tcid);
            }

            //推送用户信息
            WxMpUser wxMpUser = WxMpInstance.getWxMp().switchoverTo(appId).getUserService().userInfo(uid);
            UserInfoResponse user = BeanUtil.copyProperties(wxMpUser, UserInfoResponse.class);
            UserInfoResponse userInfoResponse = toUserInfoResponse(wxMpUser, user, customerMsg);
            userInfoResponse.setIsSpecial(customerMsg.getIsSpecial() != 0);

            DataPacket userInfo = DataPacket.system(recordCache.getDialogId(),
                    uid, appId, userInfoResponse.toString(), ChatConstant.ChatActionEnum.USERINFO.type);
            SessionCache.write(tcid, userInfo);


            List<DataPacket> records = recordCache.getRecords();
            for (DataPacket packet : records) {
                SessionCache.write(tcid, packet);
            }
            recordCache.setRecords(system);
            return ReturnJsonUtil.ok("转接成功");
        } catch (Exception e) {
            e.printStackTrace();
            return ReturnJsonUtil.fail("转接失败", e.getMessage());
        }
    }

    @Override
    public ResponseData finishUser(String cid, String uid, String appId, String type) {
        try {
            if (!SessionCache.isSession(cid)) {
                return ReturnJsonUtil.fail("您已离线，请刷新页面重新连接！");
            }
            ImChatRecordCache imChatRecordCache = ImChatRecordCache.getInstance(uid);
            if (Fc.isNull(imChatRecordCache)) {
                return ReturnJsonUtil.fail("会话信息不存在");
            }
            TblCustomerMsg tblCustomerMsg = customerMsgService.getById(imChatRecordCache.getDialogId());
            TblCustomerMsg msg = new TblCustomerMsg();
            msg.setId(imChatRecordCache.getDialogId());
            msg.setStatus(DBConstant.CustomerMsgEnum.FINISH.getType());
            msg.setCompleteCid(cid);
            msg.setData(JSON.toJSONString(imChatRecordCache.getRecords()));
            msg.setType(type);
            if (!customerMsgService.modifyById(msg)) {
                return ReturnJsonUtil.fail("修改会话信息失败");
            }
            DataPacket system = DataPacket.system(imChatRecordCache.getDialogId(), uid, appId, "系统消息：已经断开连接", ChatConstant.ChatActionEnum.CUSTOMER_USER_MESSAGE.type);
            SessionCache.write(cid, system);
            imChatRecordCache.remove();

            WxMpKefuMessage.MsgMenu msgMenu1 = new WxMpKefuMessage.MsgMenu(tblCustomerMsg.getMsgId(), ChatConstant.ReplyEnum.SATISFIED.value);
            WxMpKefuMessage.MsgMenu msgMenu2 = new WxMpKefuMessage.MsgMenu(tblCustomerMsg.getMsgId(), ChatConstant.ReplyEnum.NOSATISFIED.value);
            WxMpKefuMessage.MsgMenu msgMenu3 = new WxMpKefuMessage.MsgMenu(tblCustomerMsg.getMsgId(), ChatConstant.ReplyEnum.ORDINARY.value);
            WxMsgMenuBuilder wxMsgMenuBuilder = WxMpKefuMessage.MSGMENU().addMenus(msgMenu1, msgMenu2, msgMenu3).headContent("您本次咨询已结束，感谢您的咨询！请您对本次服务作出评价！\n");
            boolean flag = WxMpInstance.getWxMp().switchoverTo(appId).getKefuService().sendKefuMessage(wxMsgMenuBuilder.toUser(uid).build());

            if (!flag) {
                return ReturnJsonUtil.fail("发送评价消息失败");
            }
            return ReturnJsonUtil.ok("操作成功");
        } catch (Exception e) {
            e.printStackTrace();
            return ReturnJsonUtil.fail("完成失败", e.getMessage());
        }
    }

    @Override
    public ResponseData sendFile(MultipartFile media, String appId, String receiveId, String sendId) throws IOException {
        try {
            String contentType = media.getContentType();

            //给微信用户发送消息
            if (Fc.isNull(contentType) || !contentType.contains("image")) {
                return ReturnJsonUtil.fail("类型错误");
            }

            //保存文件到本地并保存数据库
            String path = MultipartFileUtil.saveFile(media, "jpg,png", properties.getFilePath());
            TbChatFile file = new TbChatFile();
            file.setFileRealName(media.getOriginalFilename());
            file.setFilePath(properties.getFilePath() + path);
            chatFileDao.save(file);


            WxMediaUploadResult wxMediaUploadResult =
                    WxMpInstance.getWxMp().switchoverTo(appId).getMaterialService().mediaUpload(WxConsts.MaterialType.IMAGE, new File(properties.getFilePath() + path));
            if (Fc.isNull(wxMediaUploadResult)) {
                return ReturnJsonUtil.fail("上传临时素材失败");
            }
            WxMpInstance.getWxMp().switchoverTo(appId).getKefuService().sendKefuMessage(WxMpKefuMessage.IMAGE().toUser(receiveId).mediaId(wxMediaUploadResult.getMediaId()).build());
            //推送消息给客服
            ImChatRecordCache imChatRecordCache = ImChatRecordCache.getInstance(receiveId);
            DataPacket dataPacket = new DataPacket();
            dataPacket.setDialogId(imChatRecordCache.getDialogId());
            dataPacket.setAction(ChatConstant.ChatActionEnum.CUSTOMER_USER_MESSAGE.type);
            dataPacket.setType(ChatConstant.MessageTypeEnum.IMAGE.type);
            dataPacket.setAppId(appId);
            dataPacket.setSendType(ChatConfigConstant.UserType.CUSTOMER);
            dataPacket.setSendId(sendId);
            dataPacket.setReceiveId(receiveId);
            dataPacket.setReceiveType(ChatConfigConstant.UserType.OTHER);
            dataPacket.setContent(file.getId());
            dataPacket.setDate(System.currentTimeMillis());
            SessionCache.write(sendId, dataPacket);
            imChatRecordCache.setRecords(dataPacket);
            return ReturnJsonUtil.ok("发送成功");
        } catch (WxErrorException e) {
            log.error("发送图片报错={}",ExceptionsUtil.getStackTraceAsString(e));
            return ReturnJsonUtil.fail("发送失败", e.getMessage());
        }
    }

    @Override
    public ResponseData offLine(String cid, String tcid, String uid, String openId, String appId) {
        try {
            if (cid.equals(tcid)) {
                return ReturnJsonUtil.fail("不可转接给自己");
            }
            if (!SessionCache.isSession(cid)) {
                return ReturnJsonUtil.fail("该客服不在线无法转接");
            }
            ImChatRecordCache imChatRecordCache = ImChatRecordCache.getInstance(uid);
            if (Fc.isNull(imChatRecordCache)) {
                return ReturnJsonUtil.fail("会话不存在");
            }
            TblCustomerMsg msg = new TblCustomerMsg();
            msg.setId(imChatRecordCache.getDialogId());
            msg.setCurrentCid(tcid);
            msg.setStatus(DBConstant.CustomerMsgEnum.OFFLINEACCESSED.getType());
            if (!customerMsgService.modifyById(msg)) {
                return ReturnJsonUtil.fail("修改会话记录失败");
            } else {
                imChatRecordCache.setCid(tcid);
            }

            long count = customerMsgService.count(new QueryWrapper<TblCustomerMsg>().lambda().eq(TblCustomerMsg::getCurrentCid, tcid)
                    .eq(TblCustomerMsg::getStatus, DBConstant.CustomerMsgEnum.OFFLINEACCESSED.getType()));
            WxMpTemplateMessage wxTemplateRequest = getWxTemplateRequest(openId, count, tcid);

            String s = WxMpInstance.getWxMp().getTemplateMsgService().sendTemplateMsg(wxTemplateRequest);
            if (Fc.isBlank(s)) {
                TblCustomerMsg customerMsg = new TblCustomerMsg();
                customerMsg.setId(imChatRecordCache.getDialogId());
                customerMsg.setCurrentCid(cid);
                customerMsg.setStatus(DBConstant.CustomerMsgEnum.ACCESSED.getType());
                customerMsgService.modifyById(customerMsg);
                imChatRecordCache.setCid(cid);
                return ReturnJsonUtil.fail("推送消息失败");
            }
            //生成系统消息并保存
            DataPacket system = DataPacket.system(imChatRecordCache.getDialogId(), tcid, appId, "系统消息：坐席 <" + cid + ">,给坐席<" + tcid + ">转接了一个用户！",
                    ChatConstant.ChatActionEnum.CUSTOMER_USER_MESSAGE.type);
            imChatRecordCache.setRecords(system);
            return ReturnJsonUtil.ok("转接离线客服成功");
        } catch (WxErrorException e) {
            e.printStackTrace();
            return ReturnJsonUtil.fail("转接离线客服失败");
        }
    }

    @Override
    public void showFile(String id) throws IOException {

        TbChatFile tbChatFile = chatFileDao.getById(id);

        if (Fc.isNull(tbChatFile)) {
            throw new BusinessException("文件不存在，无法下载");
        }

        File file = new File(tbChatFile.getFilePath());

        if (!file.exists()) {
            throw new BusinessException(file.getName() + "file不存在，无法下载");
        }

        Integer is = FileUtil.download(file, WebUtil.getResponse(), file.getName());
        if (is != 0) {
            throw new BusinessException(file.getName() + "文件下载失败");
        }
    }

    @Override
    public void forcedEnd(String openid) {
        ImChatRecordCache cache = ImChatRecordCache.getInstance(openid);
        if (Fc.isNull(cache)) {
            return;
        }
        String dialogId = cache.getDialogId();
        TblCustomerMsg tblCustomerMsg = customerMsgService.getById(dialogId);
        List<DataPacket> records = cache.getRecords();
        tblCustomerMsg.setData(JSON.toJSONString(records));
        tblCustomerMsg.setStatus(DBConstant.CustomerMsgEnum.NOTFINISSH.getType());
        customerMsgService.updateById(tblCustomerMsg);
        cache.remove();
    }


    private UserInfoResponse toUserInfoResponse(WxMpUser wxMpUser, UserInfoResponse response, TblCustomerMsg customerMsg) {
        response.setOpenid(wxMpUser.getOpenId());
        response.setSubscribe(wxMpUser.getSubscribe() ? 1 : 0);
        response.setHeadimgurl(wxMpUser.getHeadImgUrl());
        response.setUnionid(wxMpUser.getUnionId());
        response.setRemark(wxMpUser.getRemark());
        response.setDialogId(customerMsg.getId());
        response.setName(customerMsg.getName());
        response.setCity(customerMsg.getCity());
        response.setAddress(customerMsg.getAddress());
        return response;
    }

    private WxMpTemplateMessage getWxTemplateRequest(String openid, long num, String tcid) {

        WxMpTemplateMessage wxTemplateRequest = new WxMpTemplateMessage();
        wxTemplateRequest.setToUser(openid);
        wxTemplateRequest.setTemplateId(properties.getOffLineId());
        wxTemplateRequest.setUrl(properties.getOffLineUrl() + tcid);
        ArrayList<WxMpTemplateData> dataList = new ArrayList<>();
        WxMpTemplateData data1 = new WxMpTemplateData();
        data1.setName("first");
        data1.setValue("您好，收到坐席咨询信息");
        WxMpTemplateData data2 = new WxMpTemplateData();
        data2.setName("keyword1");
        data2.setValue(String.valueOf(num));
        WxMpTemplateData data3 = new WxMpTemplateData();
        data3.setName("keyword2");
        data3.setValue(DateUtil.now());
        WxMpTemplateData data4 = new WxMpTemplateData();
        data4.setName("remark");
        data4.setValue("请点击卡片处理");
        dataList.add(data1);
        dataList.add(data2);
        dataList.add(data3);
        dataList.add(data4);
        wxTemplateRequest.setData(dataList);
        return wxTemplateRequest;
    }
}
